package libs

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/fsnotify/fsnotify"
)

func WatchFiles(watcher *fsnotify.Watcher) {
	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			if filepath.Base(event.Name) == "EditToServer.json" && event.Op&fsnotify.Write == fsnotify.Write {
				fmt.Printf("配置文件已修改，正在重启程序...\n")
				restartProgram()
				return
			}
			handleFileChange(event)
		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			fmt.Printf("监听错误: %v\n", err)
		}
	}
}

func restartProgram() {
	executable, err := os.Executable()
	if err != nil {
		DebugPrint("获取可执行文件路径失败: %v\n", err)
		return
	}

	cmd := exec.Command(executable, os.Args[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin

	err = cmd.Start()
	if err != nil {
		DebugPrint("重启程序失败: %v\n", err)
		return
	}

	DebugPrint("新程序已启动，当前程序即将退出\n")
	os.Exit(0)
}

func handleFileChange(event fsnotify.Event) {
	fileMutex.Lock()
	lastTime, exists := recentFiles[event.Name]
	now := time.Now()

	if exists && now.Sub(lastTime) < time.Duration(Config.ListenDelay)*time.Millisecond {
		recentFiles[event.Name] = now
		fileMutex.Unlock()
		DebugPrint("文件 %s 的变更被延迟处理，将在 %d 毫秒后处理最后一次变更\n", event.Name, Config.ListenDelay)
		go func() {
			time.Sleep(time.Duration(Config.ListenDelay) * time.Millisecond)
			handleDelayedFileChange(event)
		}()
		return
	}

	recentFiles[event.Name] = now
	fileMutex.Unlock()

	if isIgnored(event.Name) {
		return
	}

	var action string
	switch {
	case event.Op&fsnotify.Create == fsnotify.Create:
		action = "CREATE"
	case event.Op&fsnotify.Write == fsnotify.Write:
		action = "MODIFY"
	case event.Op&fsnotify.Remove == fsnotify.Remove:
		action = "REMOVE"
	case event.Op&fsnotify.Rename == fsnotify.Rename:
		action = "RENAME"
	default:
		return
	}

	DebugPrint("文件 %s 触发 %s 操作 %s \n", event.Name, event.Op, action)

	if !contains(Config.SyncActions, action) {
		DebugPrint("跳过 %s 操作，未在 sync_actions 中配置\n", action)
		return
	}

	switch action {
	case "RENAME":
		handleRenameEvent(event.Name)
	case "CREATE":
		if isRelatedToRename(event.Name) {
			handleRenameCompletion(event.Name)
		} else {
			handleCreateOrModify(event.Name, true)
		}
	case "MODIFY":
		handleCreateOrModify(event.Name, false)
	case "REMOVE":
		sendDeleteRequestToRemote(event.Name)
	}
}

func handleDelayedFileChange(event fsnotify.Event) {
	fileMutex.Lock()
	lastChangeTime, exists := recentFiles[event.Name]
	fileMutex.Unlock()

	if !exists || time.Since(lastChangeTime) >= time.Duration(Config.ListenDelay)*time.Millisecond {
		handleFileChange(event)
	}
}
